package cn.sylinx.hbatis.ext.xmapper.xml;

import java.io.IOException;
import java.io.InputStream;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.atomic.AtomicBoolean;

import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.Element;
import org.dom4j.io.SAXReader;

import cn.sylinx.hbatis.io.ClasspathResourceScanner;
import cn.sylinx.hbatis.io.Resources;
import cn.sylinx.hbatis.kit.StrKit;
import cn.sylinx.hbatis.log.GLog;

public class XmlSqlMapper {

	private AtomicBoolean inited = new AtomicBoolean(false);

	private final SAXReader reader = new SAXReader();

	private final Map<String, Map<String, Sql>> SQL_POOL = new HashMap<String, Map<String, Sql>>();

	private static XmlSqlMapper instance = new XmlSqlMapper();

	public static XmlSqlMapper get() {
		return instance;
	}

	/**
	 * 是否已初始化
	 * 
	 * @return
	 */
	public boolean isInited() {
		return inited.get();
	}

	public void clear() {
		inited.set(false);
		SQL_POOL.clear();
	}

	private XmlSqlMapper() {
		reader.setEntityResolver(new IgnoreDTDEntityResolver());
	}

	public Sql getSqlBySqlId(String nameSpaceId_id) {

		if (StrKit.isBlank(nameSpaceId_id)) {
			return null;
		}

		if (!nameSpaceId_id.contains(".")) {
			return null;
		}

		if (!inited.get()) {
			return null;
		}

		String[] ids = nameSpaceId_id.split("\\.");
		return getSqlBySqlId(ids[0], ids[1]);
	}

	public Sql getSqlBySqlId(String nameSpaceId, String id) {

		if (!inited.get()) {
			return null;
		}

		Map<String, Sql> sqs = SQL_POOL.get(nameSpaceId);
		if (sqs == null || sqs.isEmpty()) {
			GLog.error("命名空间：" + nameSpaceId + " 没有查询语句");
			return null;
		}

		return sqs.get(id);
	}

	private void loadOne(String r) throws Exception {

		InputStream is = null;

		try {
			is = Resources.getResourceAsStream(r);
			if (is != null) {

				Document doc = reader.read(is);
				XmlSqlMapper.get().parseXml(doc);
			}
		} catch (Exception e) {

			GLog.error("load one xml error", e);
			throw e;

		} finally {

			if (is != null) {

				try {
					is.close();
				} catch (IOException e) {
				}
			}
		}

	}

	public boolean load(String resourcesPath) {

		ClasspathResourceScanner crs = new ClasspathResourceScanner(resourcesPath);
		List<String> rlist = null;

		try {
			rlist = crs.getResourceNameList();
		} catch (Exception e) {
			GLog.error("resource not found ", e);
			return false;
		}

		if (rlist == null || rlist.isEmpty()) {
			return false;
		}

		try {

			for (String r : rlist) {
				loadOne(r);
			}

		} catch (Exception e) {

			clear();
			return false;
		}

		inited.set(true);
		return true;

	}

	@SuppressWarnings("unchecked")
	private void parseXml(Document doc) throws DocumentException {

		Element nameSpace = doc.getRootElement();
		String nameSpaceId = nameSpace.element("nameSpaceId").getTextTrim();

		// 获取相应命名空间的查询语句
		Map<String, Sql> qss = SQL_POOL.get(nameSpaceId);

		if (qss == null) {
			qss = new HashMap<String, Sql>();
			SQL_POOL.put(nameSpaceId, qss);
		}

		Element sqlList = nameSpace.element("sqlList");
		// 获取每个单个查询
		List<Element> sqls = sqlList.elements("sql");
		Sql oneSql = null;
		QueryMapping mapping = null;

		for (Element sql : sqls) {

			oneSql = new Sql();
			// nameSpaceId
			oneSql.setNameSpaceId(nameSpaceId);

			// id
			String id = sql.attributeValue("id");
			oneSql.setId(id);

			// forUse
			String forUse = sql.attributeValue("forUse");
			oneSql.setForUse(forUse);

			// statement
			Element statement = sql.element("statement");
			oneSql.setStatement(statement.getTextTrim());

			// queryMapping
			Element queryMapping = sql.element("queryMapping");
			if (queryMapping != null) {

				mapping = new QueryMapping();

				// returnClass
				Element returnClass = queryMapping.element("returnClass");
				mapping.setReturnClass(returnClass.getTextTrim());

				// map
				Element map = queryMapping.element("map");
				if (map != null) {
					List<Element> entrys = map.elements("entry");
					if (entrys != null && !entrys.isEmpty()) {
						Map<String, String> kvs = new HashMap<String, String>();
						for (Element entry : entrys) {
							String key = entry.attributeValue("key");
							String value = entry.attributeValue("value");
							kvs.put(key, value);
						}
						mapping.setMap(kvs);
					}
				}

				oneSql.setQueryMapping(mapping);
			}

			qss.put(id, oneSql);
		}
	}
}
